﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using PowerTools;
using System.IO;
using System.Diagnostics;
using System.Reflection;
namespace RestSPConfigCache
{
    class Program
    {
        private static string CONFIG_DB_REG_KEY_LOC = "HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Shared Tools\\Web Server Extensions\\{0}\\Secure\\ConfigDb";
        private static string CONFIG_DB_REG_KEY_VAL = "Id";
        private static string CacheConfigLocation2003 = "{0}:\\Documents and Settings\\All Users\\Application Data\\Microsoft\\SharePoint\\Config\\{1}";
        private static string CacheConfigLocation2008 = "{0}:\\ProgramData\\Microsoft\\SharePoint\\Config\\{1}";
        private static string SHAREPOINT_TIMER_SERVICE_NAME_NO_VERSION = "SPTimerV";
        private static string SharePointVersion = "";
        private static string Welcome = "********************************************\n" +
                                        "* Welcome to Rest SP Config Cache tool 1.0 *\n" +
                                        "*     Programmed by Ahmed Farag - 2011     *\n" +
                                        "********************************************\n";
        static void Main(string[] args)
        {
            //Show the welcome message
            Console.WriteLine(Welcome);

            //Check if running with eleveated permission
            bool IsAboveWin2003 = OS.IsAboveWin2003();
            if (IsAboveWin2003 && !CheckIfRunsWithEleveatedPremissions())
            {
                return;
            }

            //Get SharePoint Config DB Guid
            string ConfigGuid = GetSharePointConfigGuid();
            if (ConfigGuid == "")
            {
                PostError("SharePoint is not Found!");
                Console.Write("Application Existing - Press any key to exit ...");
                Console.ReadLine();
                return;
            }
            string SystemDrive = OS.GetSystemDriveLetter();
            if (SystemDrive == "")
            {
                PostError("Unable to detect the system drive.\n" +
                    "Please supply the system drive letter (Ex. 'C' or 'D' ...etc):");
                SystemDrive = Console.ReadKey().KeyChar.ToString();
            }
            
            string CacheConfigLocation = IsAboveWin2003 ? CacheConfigLocation2008 : CacheConfigLocation2003;
            CacheConfigLocation = string.Format(CacheConfigLocation,SystemDrive,ConfigGuid);
            if (!Directory.Exists(CacheConfigLocation))
            {
                PostError("Unable to find the SharePoint cache files in the designated location");
                if (Directory.Exists(CacheConfigLocation.Replace("\\" + ConfigGuid, "")))
                {
                    PostWarning("Trying to reconstruct the SharePoint configuration cache folder...");
                    Directory.CreateDirectory(CacheConfigLocation);
                    PostSuccess("The SharePoint cache folder has been reconstructed successfully");
                }
                else
                {
                    Console.WriteLine("Run The SharePoint Configuration Wizard to fix your Configuration Cache");
                    Console.Write("Application Existing - Press any key to exit ...");
                    Console.ReadLine();
                    return;
                }
            }
            string SharePointTimerServiceName = SHAREPOINT_TIMER_SERVICE_NAME_NO_VERSION + SharePointVersion;
            string []FilesInCache = Directory.GetFiles(CacheConfigLocation);
            int FilesCount = FilesInCache.Length;
            bool DoesIniFileExist = File.Exists(CacheConfigLocation + "\\" + "cache.ini");
            if (!DoesIniFileExist)
            {
                PostWarning("Cache.ini file is not found. Will reconstruct a new Cache.ini file");
                StreamWriter CacheIniWriter = new StreamWriter(CacheConfigLocation + "\\" + "cache.ini");
                CacheIniWriter.Write("1");
                CacheIniWriter.Close();
                PostSuccess("A new Cache.ini file has been constructed successfully");
            }
            if (FilesCount == 0)
            {
                PostWarning("No cache files populated. Will restart the Timer service to build the cache files");
                //Stop the SharePoint Timer Service
                PostWarning("Stopping The SharePoint Timer Service ...");
                OS.StopWindowsService(SharePointTimerServiceName);
                
            }
            else
            {
                //Stop the SharePoint Timer Service
                PostWarning("Stopping The SharePoint Timer Service ...");
                OS.StopWindowsService(SharePointTimerServiceName);

                PostWarning("Cleaning old SharePoint Configuration cache files ...");

                //Delete all xml files (Clear the cache)
                foreach (string cachefile in FilesInCache)
                {
                    if (cachefile.ToLower().EndsWith(".xml"))
                        File.Delete(cachefile);
                }
                //Reset the value of the Cache.ini file
                StreamWriter CacheIniWriter = new StreamWriter(CacheConfigLocation + "\\" + "cache.ini");
                CacheIniWriter.Write("1");
                CacheIniWriter.Close();
                Console.ForegroundColor = ConsoleColor.Green;
                Console.WriteLine("SharePoint configuration cache has cleaned successfully");
                Console.ResetColor();
            }
            //Starting the SharePoint Timer Service
            PostWarning("Starting The SharePoint Timer Service ...");
            OS.StartWindowsService(SharePointTimerServiceName);
            Console.ForegroundColor = ConsoleColor.Green;
            Console.WriteLine("The SharePoint Timer Serivce has been restarted successfully.");
            Console.WriteLine("The SharePoint Configuration cache has been reset successfully.\n"+
                                "Please allow few minutes for the new cache to be constructed. ");
            Console.ResetColor();

            Console.Write("Application Existing - Press any key to exit ...");
            Console.ReadLine();

        }

        private static bool CheckIfRunsWithEleveatedPremissions()
        {
            //Check if the application is running in admin mode
            bool isElevated = PowerTools.OS.IsRunningWithElevatedPrivilages();

            if (!isElevated)
            {
                PostWarningSameLine("The command line is running without elevated privileges.\n" +
                                    "This will prevent the command line from performing the config rest successfully.\n\n" +
                                    "Do you want to restart the command with elevated privileges (Y/N)? ");
                string Result = "n";
                try
                {
                    Result = Console.ReadLine();
                }
                catch (Exception)
                {
                    
                }

                if (Result.ToLower() == "y" ||
                    Result.ToLower() == "yes")
                {
                    string ApplicationPath = OS.GetCurrentApplicationPath(Assembly.GetExecutingAssembly());
                    try
                    {
                        OS.RunApplicationWithElevatedPrivileges(ApplicationPath);
                    }
                    catch
                    {
                    }
                    return false;
                }
                else
                {
                    return true;
                }
            }
            return true;
        }

        static string GetSharePointConfigGuid()
        {
            string Result = "";
            Result = GetSharePointConfigGuid("12.0");
            if (Result == "")
                //Test SharePoint 2010 Connection
                Result = GetSharePointConfigGuid("14.0");
            else
            {
                SharePointVersion = "3";
                return Result;
            }
            if (Result == "")
                //Test SharePoint 2013 Connection
                Result = GetSharePointConfigGuid("15.0");
            else
            {
                SharePointVersion = "4";
                return Result;
            }
            if (Result == "")
                //Test SharePoint 2016 Connection
                Result = GetSharePointConfigGuid("16.0");
            else
            {
                SharePointVersion = "5";
                return Result;
            }
            if(Result !="")  SharePointVersion = "6";
            return Result;
        }
        static string GetSharePointConfigGuid(string SharePointVersion)
        {
            return OS.GetRegisteryKeyValue(string.Format(CONFIG_DB_REG_KEY_LOC, SharePointVersion), CONFIG_DB_REG_KEY_VAL);
        }
        static void PostWarning(string Message)
        {
            Console.ForegroundColor = ConsoleColor.Yellow;
            Console.WriteLine(Message);
            Console.ResetColor();
        }
        static void PostWarningSameLine(string Message)
        {
            Console.ForegroundColor = ConsoleColor.Yellow;
            Console.Write(Message);
            Console.ResetColor();
        }
        static void PostError(string Message)
        {
            Console.ForegroundColor = ConsoleColor.Red;
            Console.WriteLine(Message);
            Console.ResetColor();
        }
        static void PostSuccess(string Message)
        {
            Console.ForegroundColor = ConsoleColor.Green;
            Console.WriteLine(Message);
            Console.ResetColor();
        }
    }
}
